import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs'
import { Hero } from '../domain/heroes/hero';
import { MessagesService } from './messages.service';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class HeroService {
  private heroesUrl = 'api/heroes';
    httpOptions = {
    headers: new HttpHeaders({'Content-Type': 'application/json'})
  }
  constructor(
    private http: HttpClient,
    private messageService: MessagesService
  ) { } 

  log(message: string) {
    this.messageService.add(`HeroService ${message}`)
  }
  /**
 * Handle Http operation that failed.
 * Let the app continue.
 * @param operation - name of the operation that failed
 * @param result - optional value to return as the observable result
 */
private handleError<T> (operation = 'operation', result?: T) {
  return (error: any): Observable<T> => {
 
    // TODO: send the error to remote logging infrastructure
    console.error(error); // log to console instead
 
    // TODO: better job of transforming error for user consumption
    this.log(`${operation} failed: ${error.message}`);
 
    // Let the app keep running by returning an empty result.
    return of(result as T);
  };
}
  getHeroes(): Observable<Hero[]> {
    this.messageService.add('HeroService: fetch Heroes')
    return this.http.get<Hero[]>(this.heroesUrl).pipe(
      tap(_ => this.log('fetched heroes')),
      catchError(this.handleError<Hero[]>('getHeroes', []))
    )
  }

  getHeroe(id: Number): Observable<Hero> {
    const url = `${this.heroesUrl}/${id}`
    return this.http.get<Hero>(url).pipe(
      tap(_ => this.log(`fetched hero id=${id}`)),
      catchError(this.handleError<Hero>(`getHeroe id=${id}`))
    )
  }

  addHero(hero: Hero): Observable<any> {
    return this.http.post(this.heroesUrl, hero, this.httpOptions).pipe(
      tap(_ => this.log(`addHero hero name=${hero.name}`),
      catchError(this.handleError<any>(`addHero hero name=${hero.name}`)))
    )
  }

  updateHero(hero: Hero): Observable<any> {
    return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe(
      tap(_=> this.log(`save hero id=${hero.name}`),
      catchError(this.handleError<any>(`getHeroe name=${hero.name}`)))
    )
  }

  deleteHero(hero: Hero | number): Observable<any> {
    const id =  typeof(hero) === 'number' ? hero: hero.id
    const url = `${this.heroesUrl}/${id}`
    return this.http.delete(url, this.httpOptions).pipe(
      tap(_=> this.log(`delete hero id= ${id}`),
      catchError(this.handleError<any>(`delete hero id=${id}`)))
    )
  }

  searchHero(query: string): Observable<Hero[]> {
    if (!query.trim())  return
    const url = `${this.heroesUrl}/name=${query}`
    this.http.get(url, this.httpOptions).pipe(
      tap(_=> this.log(`searchHero nameLike= ${query}`),
      catchError(this.handleError<Hero[]>(`searchHero nameLike= ${query}`)))
    )
  } 
}
